<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title th:text="${title}">Spring Boot SSE 集群示例</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Microsoft YaHei', Arial, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            color: #333;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }

        .header {
            text-align: center;
            margin-bottom: 30px;
            color: white;
        }

        .header h1 {
            font-size: 2.5em;
            margin-bottom: 10px;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
        }

        .header p {
            font-size: 1.2em;
            opacity: 0.9;
        }

        .status-bar {
            background: rgba(255,255,255,0.95);
            padding: 15px;
            border-radius: 10px;
            margin-bottom: 20px;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
            display: flex;
            justify-content: space-between;
            align-items: center;
            flex-wrap: wrap;
        }

        .status-item {
            display: flex;
            align-items: center;
            margin: 5px;
        }

        .status-label {
            font-weight: bold;
            margin-right: 8px;
            color: #555;
        }

        .status-value {
            padding: 4px 12px;
            background: #4CAF50;
            color: white;
            border-radius: 15px;
            font-size: 0.9em;
        }

        .connection-status.disconnected .status-value {
            background: #f44336;
        }

        .main-content {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin-bottom: 30px;
        }

        @media (max-width: 768px) {
            .main-content {
                grid-template-columns: 1fr;
            }
        }

        .card {
            background: rgba(255,255,255,0.95);
            border-radius: 15px;
            padding: 20px;
            box-shadow: 0 8px 32px rgba(0,0,0,0.1);
            backdrop-filter: blur(10px);
        }

        .card h3 {
            color: #333;
            margin-bottom: 15px;
            font-size: 1.3em;
            border-bottom: 2px solid #667eea;
            padding-bottom: 8px;
        }

        .message-list {
            max-height: 400px;
            overflow-y: auto;
            border: 1px solid #ddd;
            border-radius: 8px;
            padding: 10px;
            background: #f9f9f9;
        }

        .message-item {
            margin-bottom: 10px;
            padding: 10px;
            border-radius: 8px;
            border-left: 4px solid #667eea;
            background: white;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            animation: slideIn 0.3s ease-out;
        }

        @keyframes slideIn {
            from {
                opacity: 0;
                transform: translateY(-10px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        .message-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 5px;
        }

        .message-type {
            font-weight: bold;
            color: #667eea;
        }

        .message-time {
            font-size: 0.8em;
            color: #888;
        }

        .message-content {
            font-size: 0.9em;
            color: #555;
            background: #f5f5f5;
            padding: 8px;
            border-radius: 5px;
            margin-top: 5px;
        }

        .message-node {
            font-size: 0.7em;
            color: #999;
            margin-top: 3px;
        }

        .controls {
            background: rgba(255,255,255,0.95);
            padding: 20px;
            border-radius: 15px;
            box-shadow: 0 8px 32px rgba(0,0,0,0.1);
        }

        .control-group {
            margin-bottom: 15px;
        }

        .control-group label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
            color: #333;
        }

        .control-group input, .control-group textarea {
            width: 100%;
            padding: 10px;
            border: 1px solid #ddd;
            border-radius: 5px;
            font-size: 14px;
        }

        .control-group textarea {
            height: 80px;
            resize: vertical;
        }

        .btn {
            background: #667eea;
            color: white;
            border: none;
            padding: 10px 20px;
            border-radius: 5px;
            cursor: pointer;
            font-size: 14px;
            margin-right: 10px;
            margin-bottom: 10px;
            transition: background 0.3s;
        }

        .btn:hover {
            background: #5a6fd8;
        }

        .btn.success {
            background: #4CAF50;
        }

        .btn.success:hover {
            background: #45a049;
        }

        .btn.danger {
            background: #f44336;
        }

        .btn.danger:hover {
            background: #da190b;
        }

        .message-type-system_info {
            border-left-color: #2196F3;
        }

        .message-type-user_activity {
            border-left-color: #4CAF50;
        }

        .message-type-order_update {
            border-left-color: #FF9800;
        }

        .message-type-payment_notify {
            border-left-color: #9C27B0;
        }

        .message-type-heartbeat {
            border-left-color: #607D8B;
            opacity: 0.7;
        }

        .footer {
            text-align: center;
            color: white;
            margin-top: 30px;
            opacity: 0.8;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1 th:text="${title}">Spring Boot SSE 集群示例</h1>
            <p>实时数据推送演示 - 支持集群部署</p>
        </div>

        <div class="status-bar">
            <div class="status-item connection-status" id="connectionStatus">
                <span class="status-label">连接状态:</span>
                <span class="status-value" id="connectionStatusText">未连接</span>
            </div>
            <div class="status-item">
                <span class="status-label">节点ID:</span>
                <span class="status-value" id="nodeId">-</span>
            </div>
            <div class="status-item">
                <span class="status-label">活跃连接:</span>
                <span class="status-value" id="activeConnections">-</span>
            </div>
            <div class="status-item">
                <span class="status-label">接收消息:</span>
                <span class="status-value" id="messageCount">0</span>
            </div>
        </div>

        <div class="main-content">
            <div class="card">
                <h3>📡 实时消息流</h3>
                <div class="message-list" id="messageList">
                    <div style="text-align: center; color: #999; padding: 20px;">
                        点击"连接SSE"开始接收实时消息...
                    </div>
                </div>
            </div>

            <div class="card">
                <h3>⚡ 消息统计</h3>
                <div id="messageStats">
                    <canvas id="statsChart" width="400" height="200"></canvas>
                </div>
            </div>
        </div>

        <div class="controls">
            <h3>🛠️ 控制面板</h3>
            
            <div class="control-group">
                <button class="btn success" onclick="connectSSE()">连接SSE</button>
                <button class="btn danger" onclick="disconnectSSE()">断开连接</button>
                <button class="btn" onclick="clearMessages()">清空消息</button>
                <button class="btn" onclick="getStatus()">获取状态</button>
            </div>

            <div class="control-group">
                <label for="customMessageType">自定义消息类型:</label>
                <input type="text" id="customMessageType" placeholder="例如: custom_event" value="custom_event">
            </div>

            <div class="control-group">
                <label for="customMessageContent">自定义消息内容:</label>
                <textarea id="customMessageContent" placeholder='例如: {"message": "这是一条自定义消息"}'>{
  "message": "这是一条自定义消息",
  "level": "info",
  "source": "用户手动触发"
}</textarea>
            </div>

            <div class="control-group">
                <button class="btn" onclick="sendCustomMessage()">发送自定义消息</button>
                <button class="btn" onclick="testBroadcast()">测试广播</button>
            </div>
        </div>

        <div class="footer">
            <p>© 2024 Spring Boot SSE 集群示例 | 使用 Server-Sent Events 技术实现实时数据推送</p>
        </div>
    </div>

    <script>
        let eventSource = null;
        let messageCount = 0;
        let messageStats = {
            system_info: 0,
            user_activity: 0,
            order_update: 0,
            payment_notify: 0,
            heartbeat: 0,
            other: 0
        };

        // 连接SSE
        function connectSSE() {
            if (eventSource !== null) {
                eventSource.close();
            }

            const clientId = 'web_client_' + Date.now();
            eventSource = new EventSource(`/api/sse/connect?clientId=${clientId}`);

            eventSource.onopen = function(event) {
                updateConnectionStatus(true);
                addLogMessage('✅ SSE连接已建立');
            };

            eventSource.onmessage = function(event) {
                handleMessage(event);
            };

            eventSource.onerror = function(event) {
                updateConnectionStatus(false);
                addLogMessage('❌ SSE连接错误');
                
                // 自动重连
                setTimeout(() => {
                    if (eventSource.readyState === EventSource.CLOSED) {
                        addLogMessage('🔄 尝试重新连接...');
                        connectSSE();
                    }
                }, 5000);
            };

            // 监听特定事件类型
            ['system_info', 'user_activity', 'order_update', 'payment_notify', 'heartbeat', 'welcome'].forEach(type => {
                eventSource.addEventListener(type, function(event) {
                    handleMessage(event);
                });
            });
        }

        // 断开SSE连接
        function disconnectSSE() {
            if (eventSource !== null) {
                eventSource.close();
                eventSource = null;
                updateConnectionStatus(false);
                addLogMessage('🔌 SSE连接已断开');
            }
        }

        // 处理接收到的消息
        function handleMessage(event) {
            try {
                const data = JSON.parse(event.data);
                addMessage(data);
                updateMessageStats(data.type);
                messageCount++;
                updateMessageCount();
            } catch (e) {
                console.error('解析消息失败:', e);
                addLogMessage('⚠️ 接收到无效消息格式');
            }
        }

        // 添加消息到列表
        function addMessage(data) {
            const messageList = document.getElementById('messageList');
            const messageItem = document.createElement('div');
            messageItem.className = `message-item message-type-${data.type}`;
            
            const formatContent = (content) => {
                if (typeof content === 'object') {
                    return JSON.stringify(content, null, 2);
                }
                return content;
            };

            messageItem.innerHTML = `
                <div class="message-header">
                    <span class="message-type">${getTypeDisplayName(data.type)}</span>
                    <span class="message-time">${new Date(data.timestamp).toLocaleString()}</span>
                </div>
                <div class="message-content">${formatContent(data.content)}</div>
                <div class="message-node">节点: ${data.nodeId || 'unknown'}</div>
            `;

            messageList.insertBefore(messageItem, messageList.firstChild);

            // 限制显示的消息数量
            while (messageList.children.length > 50) {
                messageList.removeChild(messageList.lastChild);
            }
        }

        // 添加日志消息
        function addLogMessage(message) {
            const logData = {
                type: 'log',
                content: message,
                timestamp: new Date().toISOString(),
                nodeId: 'client'
            };
            addMessage(logData);
        }

        // 获取类型显示名称
        function getTypeDisplayName(type) {
            const typeMap = {
                'system_info': '📊 系统信息',
                'user_activity': '👤 用户活动',
                'order_update': '📦 订单更新',
                'payment_notify': '💰 支付通知',
                'heartbeat': '💓 心跳检测',
                'welcome': '👋 欢迎消息',
                'log': '📝 日志',
                'custom_event': '🔧 自定义事件'
            };
            return typeMap[type] || `🔔 ${type}`;
        }

        // 更新连接状态
        function updateConnectionStatus(connected) {
            const statusElement = document.getElementById('connectionStatus');
            const statusText = document.getElementById('connectionStatusText');
            
            if (connected) {
                statusElement.classList.remove('disconnected');
                statusText.textContent = '已连接';
            } else {
                statusElement.classList.add('disconnected');
                statusText.textContent = '未连接';
            }
        }

        // 更新消息计数
        function updateMessageCount() {
            document.getElementById('messageCount').textContent = messageCount;
        }

        // 更新消息统计
        function updateMessageStats(type) {
            if (messageStats.hasOwnProperty(type)) {
                messageStats[type]++;
            } else {
                messageStats.other++;
            }
            drawStatsChart();
        }

        // 绘制统计图表
        function drawStatsChart() {
            const canvas = document.getElementById('statsChart');
            const ctx = canvas.getContext('2d');
            const width = canvas.width;
            const height = canvas.height;

            ctx.clearRect(0, 0, width, height);

            const colors = ['#2196F3', '#4CAF50', '#FF9800', '#9C27B0', '#607D8B', '#795548'];
            const total = Object.values(messageStats).reduce((a, b) => a + b, 0);
            
            if (total === 0) return;

            let currentAngle = 0;
            const centerX = width / 2;
            const centerY = height / 2;
            const radius = Math.min(width, height) / 2 - 20;

            Object.entries(messageStats).forEach(([type, count], index) => {
                if (count > 0) {
                    const sliceAngle = (count / total) * 2 * Math.PI;
                    
                    ctx.beginPath();
                    ctx.moveTo(centerX, centerY);
                    ctx.arc(centerX, centerY, radius, currentAngle, currentAngle + sliceAngle);
                    ctx.closePath();
                    ctx.fillStyle = colors[index % colors.length];
                    ctx.fill();

                    // 添加标签
                    const labelAngle = currentAngle + sliceAngle / 2;
                    const labelX = centerX + Math.cos(labelAngle) * (radius * 0.7);
                    const labelY = centerY + Math.sin(labelAngle) * (radius * 0.7);
                    
                    ctx.fillStyle = 'white';
                    ctx.font = '12px Arial';
                    ctx.textAlign = 'center';
                    ctx.fillText(count.toString(), labelX, labelY);

                    currentAngle += sliceAngle;
                }
            });
        }

        // 清空消息
        function clearMessages() {
            document.getElementById('messageList').innerHTML = `
                <div style="text-align: center; color: #999; padding: 20px;">
                    消息列表已清空
                </div>
            `;
            messageCount = 0;
            messageStats = {
                system_info: 0,
                user_activity: 0,
                order_update: 0,
                payment_notify: 0,
                heartbeat: 0,
                other: 0
            };
            updateMessageCount();
            drawStatsChart();
        }

        // 获取状态
        function getStatus() {
            fetch('/api/sse/status')
                .then(response => response.json())
                .then(data => {
                    document.getElementById('nodeId').textContent = data.nodeId;
                    document.getElementById('activeConnections').textContent = data.activeConnections;
                    addLogMessage(`📈 状态更新: 活跃连接 ${data.activeConnections} 个`);
                })
                .catch(error => {
                    addLogMessage(`❌ 获取状态失败: ${error.message}`);
                });
        }

        // 发送自定义消息
        function sendCustomMessage() {
            const type = document.getElementById('customMessageType').value;
            const contentText = document.getElementById('customMessageContent').value;
            
            if (!type.trim()) {
                alert('请输入消息类型');
                return;
            }

            let content;
            try {
                content = JSON.parse(contentText);
            } catch (e) {
                content = contentText;
            }

            fetch('/api/sse/push', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    type: type,
                    content: content
                })
            })
            .then(response => response.json())
            .then(data => {
                if (data.success) {
                    addLogMessage(`✅ 自定义消息发送成功: ${type}`);
                } else {
                    addLogMessage(`❌ 自定义消息发送失败: ${data.message}`);
                }
            })
            .catch(error => {
                addLogMessage(`❌ 发送请求失败: ${error.message}`);
            });
        }

        // 测试广播
        function testBroadcast() {
            const testMessage = {
                type: 'test_broadcast',
                content: {
                    message: '这是一条测试广播消息',
                    timestamp: new Date().toISOString(),
                    testData: {
                        number: Math.floor(Math.random() * 1000),
                        boolean: Math.random() > 0.5,
                        array: ['测试', '数据', '数组']
                    }
                }
            };

            fetch('/api/sse/push', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(testMessage)
            })
            .then(response => response.json())
            .then(data => {
                if (data.success) {
                    addLogMessage('✅ 测试广播发送成功');
                } else {
                    addLogMessage(`❌ 测试广播发送失败: ${data.message}`);
                }
            })
            .catch(error => {
                addLogMessage(`❌ 发送请求失败: ${error.message}`);
            });
        }

        // 页面加载完成后初始化
        document.addEventListener('DOMContentLoaded', function() {
            drawStatsChart();
            getStatus();
            
            // 自动连接
            setTimeout(() => {
                connectSSE();
            }, 1000);
        });

        // 页面卸载时断开连接
        window.addEventListener('beforeunload', function() {
            disconnectSSE();
        });
    </script>
</body>
</html>